﻿using System;
using System.Collections;
using Google.GData.Analytics;
using Microsoft.SqlServer.Dts.Pipeline;
using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
using Microsoft.SqlServer.Dts.Runtime;
using Microsoft.SqlServer.Dts.Runtime.Wrapper;
using System.Data;

namespace SSISComponents
{
    [DtsPipelineComponent(
        DisplayName = "GoogleAnalyticsSource",
        Description = "Integrate business information and give access to Google Analytics data.",
        IconResource = "SSISComponents.GoogleAnalyticsSource.ico",
        UITypeName = "SSISComponents.GoogleAnalyticsSourceUI, SSISComponents.Dts.Pipeline.GoogleAnalyticsSource, Version=1.0.1.0, Culture=neutral, PublicKeyToken=8809941550a3df07",
        ComponentType = ComponentType.SourceAdapter)]
    public class GoogleAnalyticsSource : Microsoft.SqlServer.Dts.Pipeline.PipelineComponent
    {
        #region Members

        private ColumnCollection _Columns = new ColumnCollection();
        private IDTSCustomProperty100 IDTS_Username;
        private IDTSCustomProperty100 IDTS_Password;
        private IDTSCustomProperty100 IDTS_Profile;
        private IDTSCustomProperty100 IDTS_StartDate;
        private IDTSCustomProperty100 IDTS_EndDate;
        private IDTSCustomProperty100 IDTS_StartIndex;
        private IDTSCustomProperty100 IDTS_MaxResults;
        private IDTSCustomProperty100 IDTS_Dimensions;
        private IDTSCustomProperty100 IDTS_Metrics;
        private IDTSCustomProperty100 IDTS_DimensionsFilter;
        private IDTSCustomProperty100 IDTS_MetricsFilter;
        private IDTSCustomProperty100 IDTS_DefaultSegments;

        private AnalyticsService Service = null;
        private ArrayList m_columnInfo;
        private int _rows = 0;
        private bool bCancel;

        public const string dataFeedUrl = "https://www.google.com/analytics/feeds/data";
        //public const string LogFile = "C:\\GA_Log.txt";
        //public const bool WriteLog = true;

        /// <summary>
        /// Struct that is populated with the index of each output column in the buffer,
        /// and the name of the column at the external data source.
        /// </summary>
        private struct ColumnInfo
        {
            public int BufferColumnIndex;
            public string ColumnName;
        }

        #endregion Members

        #region Design Time

        /// <summary>
        /// ComponentProperties
        /// </summary>
        public override void ProvideComponentProperties()
        {
            base.ProvideComponentProperties();
            RemoveAllInputsOutputsAndCustomProperties();
            ComponentMetaData.Name = "GoogleAnalyticsSource";

            // add an output
            ComponentMetaData.OutputCollection.New();

            // Get the assembly version and set that as current version.
            SetComponentVersion();

            IDTS_Dimensions = ComponentMetaData.CustomPropertyCollection.New();
            IDTS_Dimensions.Name = "Dimensions";
            IDTS_Dimensions.Description = "Dimensions";
            IDTS_Dimensions.ExpressionType = DTSCustomPropertyExpressionType.CPET_NOTIFY;

            IDTS_DimensionsFilter = ComponentMetaData.CustomPropertyCollection.New();
            IDTS_DimensionsFilter.Name = "DimensionsFilter";
            IDTS_DimensionsFilter.Description = "DimensionsFilter";
            IDTS_DimensionsFilter.ExpressionType = DTSCustomPropertyExpressionType.CPET_NOTIFY;

            IDTS_EndDate = ComponentMetaData.CustomPropertyCollection.New();
            IDTS_EndDate.Name = "EndDate";
            IDTS_EndDate.Description = "EndDate";
            IDTS_EndDate.ExpressionType = DTSCustomPropertyExpressionType.CPET_NOTIFY;

            IDTS_MaxResults = ComponentMetaData.CustomPropertyCollection.New();
            IDTS_MaxResults.Name = "MaxResults";
            IDTS_MaxResults.Description = "MaxResults";
            IDTS_MaxResults.ExpressionType = DTSCustomPropertyExpressionType.CPET_NOTIFY;

            IDTS_Metrics = ComponentMetaData.CustomPropertyCollection.New();
            IDTS_Metrics.Name = "Metrics";
            IDTS_Metrics.Description = "Metrics";
            IDTS_Metrics.ExpressionType = DTSCustomPropertyExpressionType.CPET_NOTIFY;

            IDTS_MetricsFilter = ComponentMetaData.CustomPropertyCollection.New();
            IDTS_MetricsFilter.Name = "MetricsFilter";
            IDTS_MetricsFilter.Description = "MetricsFilter";
            IDTS_MetricsFilter.ExpressionType = DTSCustomPropertyExpressionType.CPET_NOTIFY;

            IDTS_Password = ComponentMetaData.CustomPropertyCollection.New();
            IDTS_Password.Name = "Password";
            IDTS_Password.Description = "Password";
            IDTS_Password.EncryptionRequired = true;
            IDTS_Password.ExpressionType = DTSCustomPropertyExpressionType.CPET_NOTIFY;

            IDTS_Profile = ComponentMetaData.CustomPropertyCollection.New();
            IDTS_Profile.Name = "Profile";
            IDTS_Profile.Description = "Profile";
            IDTS_Profile.ExpressionType = DTSCustomPropertyExpressionType.CPET_NOTIFY;

            IDTS_StartDate = ComponentMetaData.CustomPropertyCollection.New();
            IDTS_StartDate.Name = "StartDate";
            IDTS_StartDate.Description = "StartDate";
            IDTS_StartDate.ExpressionType = DTSCustomPropertyExpressionType.CPET_NOTIFY;

            IDTS_StartIndex = ComponentMetaData.CustomPropertyCollection.New();
            IDTS_StartIndex.Name = "StartIndex";
            IDTS_StartIndex.Description = "StartIndex";
            IDTS_StartIndex.ExpressionType = DTSCustomPropertyExpressionType.CPET_NOTIFY;

            IDTS_Username = ComponentMetaData.CustomPropertyCollection.New();
            IDTS_Username.Name = "Username";
            IDTS_Username.Description = "Username";
            IDTS_Username.EncryptionRequired = true;
            IDTS_Username.ExpressionType = DTSCustomPropertyExpressionType.CPET_NOTIFY;

            IDTS_DefaultSegments = ComponentMetaData.CustomPropertyCollection.New();
            IDTS_DefaultSegments.Name = "DefaultSegments";
            IDTS_DefaultSegments.Description = "DefaultSegments";
            IDTS_DefaultSegments.ExpressionType = DTSCustomPropertyExpressionType.CPET_NOTIFY;

            //IDTS_CustomSegments = ComponentMetaData.CustomPropertyCollection.New();
            //IDTS_CustomSegments.Name = "CustomSegments";
            //IDTS_CustomSegments.Description = "CustomSegments";
            //IDTS_CustomSegments.ExpressionType = DTSCustomPropertyExpressionType.CPET_NOTIFY;

            // name the output
            ComponentMetaData.OutputCollection[0].Name = "GoogleAnalyticsSource adapter output";
            ComponentMetaData.OutputCollection[0].ExternalMetadataColumnCollection.IsUsed = true;

            // validate external metadata
            ComponentMetaData.ValidateExternalMetadata = true;
        }

        /// <summary>
        /// Generates new output columns
        /// </summary>
        public override void ReinitializeMetaData()
        {
            IDTSOutput100 output = ComponentMetaData.OutputCollection[0];

            output.OutputColumnCollection.RemoveAll();
            output.ExternalMetadataColumnCollection.RemoveAll();

            // Generate the columns with metadata
            GenerateColumns();

            foreach (Column dataColumn in _Columns)
            {
                // create a new column
                IDTSOutputColumn100 outputcolNew = output.OutputColumnCollection.New();

                if (string.IsNullOrEmpty(dataColumn.Name))
                {
                    throw new PipelineComponentHResultException(HResults.DTS_E_DATASOURCECOLUMNWITHNONAMEFOUND);
                }

                outputcolNew.Name = dataColumn.Name;
                outputcolNew.SetDataTypeProperties(dataColumn.DataType, dataColumn.Length, dataColumn.Precision, dataColumn.Scale, dataColumn.Codepage);
                outputcolNew.Description = dataColumn.Description;

                CreateExternalMetaDataColumn(output.ExternalMetadataColumnCollection, outputcolNew);
            }

            // Exclusion Group
            output.ExclusionGroup = 0;

            // Synchronous Input
            output.SynchronousInputID = 0;

            base.ReinitializeMetaData();
        }

        /// <summary>
        /// Validates input data and component properties
        /// </summary>
        /// <returns></returns>
        public override DTSValidationStatus Validate()
        {
            IDTSOutput100 output = ComponentMetaData.OutputCollection[0];

            if (ComponentMetaData.InputCollection.Count != 0)
            {
                ComponentMetaData.FireError(0, ComponentMetaData.Name, "Has an input when no input should exist.", "", 0, out bCancel);
                return DTSValidationStatus.VS_ISCORRUPT;
            }

            // Validate the output columns against the external metadata?
            if (ComponentMetaData.ValidateExternalMetadata)
            {
                // output column collection match the columns at the data source?
                if (!this.AreOutputColumnsValid())
                {
                    //return DTSValidationStatus.VS_NEEDSNEWMETADATA;
                    ReinitializeMetaData();
                }

                if (!ComponentValidation.DoesExternalMetaDataMatchOutputMetaData(output))
                {
                    ComponentMetaData.FireWarning(0, ComponentMetaData.Name, "The ExternalMetaDataColumns do not match the output columns.", "", 0);
                    return DTSValidationStatus.VS_NEEDSNEWMETADATA;
                }
            }
            else
            {
                if (!ComponentValidation.DoesOutputColumnMetaDataMatchExternalColumnMetaData(ComponentMetaData.OutputCollection[0]))
                {
                    // No, post a warning, and fix the errors in ReintializeMetaData.
                    ComponentMetaData.FireWarning(0, ComponentMetaData.Name, "Output columns do not match external metadata.", "", 0);
                    return DTSValidationStatus.VS_NEEDSNEWMETADATA;
                }
            }

            // Return base class validation result.
            return base.Validate();
        }

        //=================================================================================================

        #region Overloaded insert and delete methods ( insert/delete inputs, outputs and columns )

        //public override void PerformUpgrade(int pipelineVersion)
        //{
        //    base.PerformUpgrade(pipelineVersion);
        //}

        public override IDTSInput100 InsertInput(DTSInsertPlacement insertPlacement, int inputID)
        {
            throw new PipelineComponentHResultException("You cannot insert an input", HResults.DTS_W_GENERICWARNING);
        }

        public override IDTSOutput100 InsertOutput(DTSInsertPlacement insertPlacement, int outputID)
        {
            throw new PipelineComponentHResultException("You cannot insert an output", HResults.DTS_W_GENERICWARNING);
        }

        public override void DeleteInput(int inputID)
        {
            throw new PipelineComponentHResultException("You cannot delete an input", HResults.DTS_W_GENERICWARNING);
        }

        public override void DeleteOutput(int outputID)
        {
            throw new PipelineComponentHResultException("You cannot delete an ouput", HResults.DTS_W_GENERICWARNING);
        }

        public override void DeleteExternalMetadataColumn(int iID, int iExternalMetadataColumnID)
        {
            throw new PipelineComponentHResultException("You cannot delete external metadata column", HResults.DTS_W_GENERICWARNING);
        }

        public override IDTSOutputColumn100 InsertOutputColumnAt(int outputID, int outputColumnIndex, string name, string description)
        {
            throw new PipelineComponentHResultException("You cannot add output column", HResults.DTS_W_GENERICWARNING);
        }

        public override IDTSExternalMetadataColumn100 InsertExternalMetadataColumnAt(int iID, int iExternalMetadataColumnIndex, string strName, string strDescription)
        {
            throw new PipelineComponentHResultException("You cannot add external metadata column", HResults.DTS_W_GENERICWARNING);
        }

        //=================================================================================================

        #endregion Overloaded insert and delete methods ( insert/delete inputs, outputs and columns )

        //=================================================================================================

        #endregion Design Time

        #region Runtime

        /// <summary>
        ///
        /// </summary>
        public override void PreExecute()
        {
            bool bout = true;
            ComponentMetaData.FireInformation(0, "SSIS GoogleAnalyticsSource", "PreExecution started ...", "", 0, ref bout);
            m_columnInfo = new ArrayList();
            IDTSOutput100 output = ComponentMetaData.OutputCollection[0];
            ComponentMetaData.FireInformation(0, "SSIS GoogleAnalyticsSource", output.OutputColumnCollection.Count.ToString(), "", 0, ref bout);
            foreach (IDTSOutputColumn100 col in output.OutputColumnCollection)
            {
                ColumnInfo ci = new ColumnInfo();
                ci.BufferColumnIndex = BufferManager.FindColumnByLineageID(output.Buffer, col.LineageID);
                ci.ColumnName = col.Name;
                m_columnInfo.Add(ci);
            }
            ComponentMetaData.FireInformation(0, "SSIS GoogleAnalyticsSource", "PreExecution finished.", "", 0, ref bout);
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="outputs"></param>
        /// <param name="outputIDs"></param>
        /// <param name="buffers"></param>
        public override void PrimeOutput(int outputs, int[] outputIDs, PipelineBuffer[] buffers)
        {
            PipelineBuffer buffer = buffers[0];
            bool bout = true;
            try
            {
                ComponentMetaData.FireInformation(0, "SSIS GoogleAnalyticsSource", "Profile ID: " + ComponentMetaData.CustomPropertyCollection["Profile"].Value.ToString(), "", 0, ref bout);

                Service = new AnalyticsService("SSISGoogleAnalytics");
                Service.setUserCredentials(ComponentMetaData.CustomPropertyCollection["Username"].Value.ToString(), ComponentMetaData.CustomPropertyCollection["Password"].Value.ToString());

                DataQuery query = new DataQuery(SSISComponents.GoogleAnalyticsSource.dataFeedUrl);
                query.Ids = ComponentMetaData.CustomPropertyCollection["Profile"].Value.ToString();

                ComponentMetaData.FireInformation(0, "SSIS GoogleAnalyticsSource", query.Ids, "", 0, ref bout);

                string strMetricsFilter = null;
                string strDimensionsFilter = null;

                if (ComponentMetaData.CustomPropertyCollection["MetricsFilter"].Value != null)
                {
                    try
                    {
                        strMetricsFilter = ComponentMetaData.CustomPropertyCollection["MetricsFilter"].Value.ToString();
                        ComponentMetaData.FireInformation(0, "SSIS GoogleAnalyticsSource", GoogleAnalytics.parseProperty(strMetricsFilter), "", 0, ref bout);
                    }
                    catch { }
                }

                if (ComponentMetaData.CustomPropertyCollection["DimensionsFilter"].Value != null)
                {
                    try
                    {
                        strDimensionsFilter = ComponentMetaData.CustomPropertyCollection["DimensionsFilter"].Value.ToString();
                        ComponentMetaData.FireInformation(0, "SSIS GoogleAnalyticsSource", GoogleAnalytics.parseProperty(strDimensionsFilter), "", 0, ref bout);
                    }
                    catch { }
                }

                query.Filters = GoogleAnalytics.FilterCombine(GoogleAnalytics.parseProperty(strMetricsFilter), GoogleAnalytics.parseProperty(strDimensionsFilter));
                
                query.Metrics = ComponentMetaData.CustomPropertyCollection["Metrics"].Value.ToString().Replace('|', ',');
                query.Dimensions = ComponentMetaData.CustomPropertyCollection["Dimensions"].Value.ToString().Replace('|', ',');
                query.Segment = ComponentMetaData.CustomPropertyCollection["DefaultSegments"].Value.ToString();
                query.GAStartDate = ComponentMetaData.CustomPropertyCollection["StartDate"].Value.ToString();
                query.GAEndDate = ComponentMetaData.CustomPropertyCollection["EndDate"].Value.ToString();

                ComponentMetaData.FireInformation(0, "SSIS GoogleAnalyticsSource", query.Metrics, "", 0, ref bout);
                ComponentMetaData.FireInformation(0, "SSIS GoogleAnalyticsSource", query.Dimensions, "", 0, ref bout);
                ComponentMetaData.FireInformation(0, "SSIS GoogleAnalyticsSource", query.GAStartDate, "", 0, ref bout);
                ComponentMetaData.FireInformation(0, "SSIS GoogleAnalyticsSource", query.GAEndDate, "", 0, ref bout);


                //if (Convert.ToInt16(ComponentMetaData.CustomPropertyCollection["StartIndex"].Value.ToString()) > 0)
                //{
                //    query.StartIndex = Convert.ToInt16(ComponentMetaData.CustomPropertyCollection["StartIndex"].Value.ToString());
                //}

                //if (Convert.ToInt16(ComponentMetaData.CustomPropertyCollection["MaxResults"].Value.ToString()) > 0)
                //{
                //    query.NumberToRetrieve = Convert.ToInt16(ComponentMetaData.CustomPropertyCollection["MaxResults"].Value.ToString());
                //}

                //WriteComponentInformation(query);

                try
                {
                    Boolean MoreData = true;
                    //int intThousand = 1;
                    int StartIndex = 0;
                    while (MoreData == true)
                    {
                        //StartIndex += ((intThousand * 10000));
                        query.StartIndex = StartIndex;
                        DataTable data = GoogleAnalytics.AsDataTable(Service.Query(query), query);
                        if (data.Rows.Count < 1000) MoreData = false;

                        //ComponentMetaData.FireInformation(0, "GoogleAnalyticsSource", "Datarows: " + data.Rows.Count.ToString(), "", 0, ref bout);

                        foreach (DataRow row in data.Rows)
                        {
                            buffer.AddRow();
                            _rows += 1;
                            int colCount = 0;
                            object Value = null;
                            foreach (Column col in _Columns)
                            {
                                switch (col.DataType)
                                {
                                    case DataType.DT_BOOL:
                                        switch (row[col.Name].ToString().ToUpper())
                                        {
                                            case "YES":
                                                Value = Convert.ToBoolean("true");
                                                break;
                                            case "NO":
                                                Value = Convert.ToBoolean("false");
                                                break;
                                            case "1":
                                                Value = Convert.ToBoolean("true");
                                                break;
                                            case "0":
                                                Value = Convert.ToBoolean("false");
                                                break;
                                            default:
                                                Value = Convert.ToBoolean("false");
                                                break;
                                        }
                                        break;
                                    case DataType.DT_WSTR:
                                        Value = Convert.ToString(row[col.Name]);
                                        if (Value.ToString().Length > 4000)
                                        {
                                            Value = row[col.Name].ToString().Substring(0, 4000);
                                            ComponentMetaData.FireInformation(0, "SSIS GoogleAnalyticsSource", "\"" + col.Name + "\"-value was truncated to 4000 chars." + " rows processed", null, 0, ref bout);
                                        }
                                        break;
                                    default:
                                        Value = row[col.Name];
                                        break;
                                }
                                
                                buffer[colCount] = Value;
                                colCount++;

                            }
                            if (_rows % 1000 == 0)
                            {
                                ComponentMetaData.FireInformation(0, "SSIS GoogleAnalyticsSource", _rows.ToString() + " rows processed", null, 0, ref bout);
                            }
                        }

                        StartIndex += 1001;

                    }
                }
                catch (System.Runtime.InteropServices.COMException ex)
                {
                    //ExceptionWriter(ex.ToString());
                    ComponentMetaData.FireError(0, "SSIS GoogleAnalyticsSource", ex.ToString(), "", 0, out bCancel);
                }
                catch (Exception ex)
                {
                    //ExceptionWriter(ex.ToString());
                    ComponentMetaData.FireError(0, "SSIS GoogleAnalyticsSource", ex.ToString(), "", 0, out bCancel);
                }

                ComponentMetaData.FireInformation(0, "SSIS GoogleAnalyticsSource", "Component wrote " + _rows.ToString() + " rows.", null, 0, ref bout);
            }
            catch (System.Runtime.InteropServices.COMException ex)
            {
                //ExceptionWriter(ex.ToString());
                ComponentMetaData.FireError(0, "SSIS GoogleAnalyticsSource", ex.ToString(), "", 0, out bCancel);
            }
            catch (Exception ex)
            {
                //ExceptionWriter(ex.ToString());
                
                //The 'if' and 'else' parts of this statement are identical
                //if (Convert.ToBoolean(ComponentMetaData.CustomPropertyCollection["IgnoreConversionError"].Value) != true)
                //{
                //    //ComponentMetaData.FireError(0, "SSIS GoogleAnalyticsSource", "An error occured during processing.", "", 0, out bCancel);
                //    ComponentMetaData.FireWarning(0, "SSIS GoogleAnalyticsSource", ex.ToString(), "", 0);
                //}
                //else
                //{
                //    ComponentMetaData.FireWarning(0, "SSIS GoogleAnalyticsSource", ex.ToString(), "", 0);
                //}
                ComponentMetaData.FireWarning(0, "SSIS GoogleAnalyticsSource", ex.ToString(), "", 0);
            }
            finally
            {
                buffer.SetEndOfRowset();
            }
        }

        /// <summary>
        /// Called at the end of the execution of a component.
        /// </summary>
        public override void PostExecute()
        {
            base.PostExecute();
        }

        #endregion Runtime

        #region Helpers

        /// <summary>
        /// Create an external metadata column for each output. Map the two
        /// by setting the ExternalMetaDataColumnID property of the output to
        /// the external metadata column.
        /// </summary>
        /// <param name="output">The output the columns are added to.</param>
        private static void CreateExternalMetaDataColumn(IDTSExternalMetadataColumnCollection100 externalCollection, IDTSOutputColumn100 column)
        {
            // For each output column create an external meta data columns.
            IDTSExternalMetadataColumn100 eColumn = externalCollection.New();
            eColumn.Name = column.Name;
            eColumn.DataType = column.DataType;
            eColumn.Precision = column.Precision;
            eColumn.Length = column.Length;
            eColumn.Scale = column.Scale;

            // wire the output column to the external metadata
            column.ExternalMetadataColumnID = eColumn.ID;
        }

        /// <summary>
        /// Generate ColumnCollection for External Metadata,
        /// Custom Properties and some more
        /// </summary>
        private void GenerateColumns()
        {
            try
            {
                if (ComponentMetaData.CustomPropertyCollection["Profile"].Value != null &&
                    ComponentMetaData.CustomPropertyCollection["Metrics"].Value != null &&
                    ComponentMetaData.CustomPropertyCollection["Dimensions"].Value != null)
                {
                    _Columns.Clear();
                    string[] arrMetrics = ComponentMetaData.CustomPropertyCollection["Metrics"].Value.ToString().Split('|');
                    string[] arrDimensions = ComponentMetaData.CustomPropertyCollection["Dimensions"].Value.ToString().Split('|');
                    string[] Columns = new string[arrMetrics.Length + arrDimensions.Length];
                    ComponentMetaData.CustomPropertyCollection["Dimensions"].Value.ToString().Split('|').CopyTo(Columns, 0);
                    ComponentMetaData.CustomPropertyCollection["Metrics"].Value.ToString().Split('|').CopyTo(Columns, arrDimensions.Length);

                    for (int i = 0; i < Columns.Length; i++)
                    {
                        //int ColumnsLength;

                        //if (Columns[i].IndexOf("Path") > 0)
                        //{
                        //    ColumnsLength = 4000;
                        //}
                        //else
                        //{
                        //    ColumnsLength = 255;
                        //}
                        
                        GoogleDimensions Dim = new GoogleDimensions();
                        GoogleMetrics Met = new GoogleMetrics();
                        int Codepage = 0;
                        int Length = 0;
                        int Precision = 0;
                        int Scale = 0;
                        DataType DataType = GetDataType("DT_WSTR");
                        try
                        {
                            if (Dim.Exist(Columns[i]))
                            {
                                Length = LConvert(Dim.GetLength(Columns[i].ToString()));
                                Precision = LConvert(Dim.GetPrecision(Columns[i].ToString()));
                                Scale = LConvert(Dim.GetScale(Columns[i].ToString()));
                                DataType = GetDataType(Dim.GetDataType(Columns[i].ToString()));
                            }
                            else if (Met.Exist(Columns[i]))
                            {
                                Length = LConvert(Met.GetLength(Columns[i].ToString()));
                                Precision = LConvert(Met.GetPrecision(Columns[i].ToString()));
                                Scale = LConvert(Met.GetScale(Columns[i].ToString()));
                                DataType = GetDataType(Met.GetDataType(Columns[i].ToString()));
                            }
                        }
                        catch(Exception ex)
                        {
                            //ExceptionWriter(ex.ToString());
                            Codepage = 0;
                            Length = 0;
                            Precision = 0;
                            Scale = 0;
                            DataType = GetDataType("DT_WSTR");
                        }

                        _Columns.Add(Columns[i], DataType, Length, Precision, Scale, Codepage);
                    }
                }
            }
            catch (Exception ex)
            {
                ComponentMetaData.FireError(HResults.DTS_E_VALIDATIONFAILED, ComponentMetaData.Name, ex.ToString(), "", 0, out bCancel);
            }
        }

        //private void ExceptionWriter(string Value)
        //{
        //    try
        //    {
        //        string LogFile = IDTS_LogFile.ToString();
        //        if (IDTS_WriteLog.ToString().ToUpper() == "TRUE" && LogFile != null)
        //        {
        //            using (System.IO.TextWriter streamWriter = new System.IO.StreamWriter(LogFile))
        //            {
        //                streamWriter.Write(DateTime.Now.ToString() + ": " + Value);
        //            }
        //        }
        //    }
        //    catch (Exception ex)
        //    {
        //        ComponentMetaData.FireError(HResults.DTS_E_VALIDATIONFAILED, ComponentMetaData.Name, ex.ToString(), "", 0, out bCancel);
        //    }
        //}

        private int LConvert(string Value)
        {
            int _return = 0;
            try
            {
                if (Value == null)
                {
                    _return = 0;
                }
                else
                {
                    _return = Convert.ToInt32(Value);
                }
            }
            catch
            {
                _return = 0;
            }
            return _return;
        }

        /// <summary>
        /// Checks if each output column is valid
        /// </summary>
        /// <returns></returns>
        private bool AreOutputColumnsValid()
        {
            IDTSOutput100 output = ComponentMetaData.OutputCollection[0];
            GenerateColumns();

            // Output columns should be subset of external columns
            if (output.OutputColumnCollection.Count != _Columns.Count)
            {
                return false;
            }

            // Otherwise, walk the WQL columns and validate each column
            for (int x = 0; x < output.OutputColumnCollection.Count; x++)
            {
                IDTSOutputColumn100 column = output.OutputColumnCollection[x];

                Column Col = _Columns.GetColumnByName(column.Name);

                // Does the column exist, by name, in the WQL schema?
                if (Col == null || !ColumnMatchesOutputColumn(Col, column))
                {
                    // Fire a warning before returning
                    ComponentMetaData.FireWarning(0, ComponentMetaData.Name, "The output column " + column.IdentificationString + " does not match the data source.", "", 0);
                    return false;
                }
            }

            // If this code is reached, all of the columns are valid.
            return true;
        }

        /// <summary>
        /// Checks if each internal column match to the corresponding output column
        /// </summary>
        /// <param name="Col"></param>
        /// <param name="column"></param>
        /// <returns></returns>
        private bool ColumnMatchesOutputColumn(Column Col, IDTSOutputColumn100 column)
        {
            DataType dt = Col.DataType;
            int length = Col.Length;
            int scale = Col.Scale;
            int codePage = Col.Codepage;

            if (dt == column.DataType && length == column.Length && scale == column.Scale && codePage == column.CodePage)
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// Gets the ssis datatype
        /// </summary>
        /// <param name="DT"></param>
        /// <returns></returns>
        private DataType GetDataType(string DT)
        {
            switch (DT)
            {
                case "DT_BOOL": return DataType.DT_BOOL;
                case "DT_BYTES": return DataType.DT_BYTES;
                case "DT_CY": return DataType.DT_CY;
                case "DT_DATE": return DataType.DT_DATE;
                case "DT_DBDATE": return DataType.DT_DBDATE;
                case "DT_DBTIME": return DataType.DT_DBTIME;
                case "DT_DBTIME2": return DataType.DT_DBTIME2;
                case "DT_DBTIMESTAMP": return DataType.DT_DBTIMESTAMP;
                case "DT_DBTIMESTAMP2": return DataType.DT_DBTIMESTAMP2;
                case "DT_DBTIMESTAMPOFFSET": return DataType.DT_DBTIMESTAMPOFFSET;
                case "DT_DECIMAL": return DataType.DT_DECIMAL;
                case "DT_EMPTY": return DataType.DT_EMPTY;
                case "DT_FILETIME": return DataType.DT_FILETIME;
                case "DT_GUID": return DataType.DT_GUID;
                case "DT_I1": return DataType.DT_I1;
                case "DT_I2": return DataType.DT_I2;
                case "DT_I4": return DataType.DT_I4;
                case "DT_I8": return DataType.DT_I8;
                case "DT_IMAGE": return DataType.DT_IMAGE;
                case "DT_NTEXT": return DataType.DT_NTEXT;
                case "DT_NULL": return DataType.DT_NULL;
                case "DT_NUMERIC": return DataType.DT_NUMERIC;
                case "DT_R4": return DataType.DT_R4;
                case "DT_R8": return DataType.DT_R8;
                case "DT_STR": return DataType.DT_STR;
                case "DT_TEXT": return DataType.DT_TEXT;
                case "DT_UI1": return DataType.DT_UI1;
                case "DT_UI2": return DataType.DT_UI2;
                case "DT_UI4": return DataType.DT_UI4;
                case "DT_UI8": return DataType.DT_UI8;
                case "DT_WSTR": return DataType.DT_WSTR;
                default: return DataType.DT_WSTR;
            }
        }

        /// <summary>
        /// Set the componet version to match the assembly version.
        /// </summary>
        public void SetComponentVersion()
        {
            // Get the assembly version and set that as our current version.
            DtsPipelineComponentAttribute attr = (DtsPipelineComponentAttribute)Attribute.GetCustomAttribute(this.GetType(), typeof(DtsPipelineComponentAttribute), false);
            System.Diagnostics.Trace.Assert(attr != null, "Could not get attributes");
            ComponentMetaData.Version = attr.CurrentVersion;
        }

        /// <summary>
        /// Fire DataQuery Information
        /// </summary>
        /// <param name="query"></param>
        public void WriteComponentInformation(DataQuery query)
        {
            bool bout = true;
            ComponentMetaData.FireInformation(0, "SSIS GoogleAnalyticsSource", "Credentials: " + Service.Credentials.ToString(), "", 0, ref bout);
            ComponentMetaData.FireInformation(0, "SSIS GoogleAnalyticsSource", "URL: " + dataFeedUrl, "", 0, ref bout);
            ComponentMetaData.FireInformation(0, "SSIS GoogleAnalyticsSource", "Profile: " + ComponentMetaData.CustomPropertyCollection["Profile"].Value.ToString(), "", 0, ref bout);
            ComponentMetaData.FireInformation(0, "SSIS GoogleAnalyticsSource", "Dimensions: " + ComponentMetaData.CustomPropertyCollection["Dimensions"].Value.ToString(), "", 0, ref bout);
            ComponentMetaData.FireInformation(0, "SSIS GoogleAnalyticsSource", "Metrics: " + ComponentMetaData.CustomPropertyCollection["Metrics"].Value.ToString(), "", 0, ref bout);
            ComponentMetaData.FireInformation(0, "SSIS GoogleAnalyticsSource", "StartDate: " + ComponentMetaData.CustomPropertyCollection["StartDate"].Value.ToString(), "", 0, ref bout);
            ComponentMetaData.FireInformation(0, "SSIS GoogleAnalyticsSource", "EndDate: " + ComponentMetaData.CustomPropertyCollection["EndDate"].Value.ToString(), "", 0, ref bout);
            ComponentMetaData.FireInformation(0, "SSIS GoogleAnalyticsSource", "StartIndex: " + ComponentMetaData.CustomPropertyCollection["StartIndex"].Value.ToString(), "", 0, ref bout);
            ComponentMetaData.FireInformation(0, "SSIS GoogleAnalyticsSource", "MaxResults: " + ComponentMetaData.CustomPropertyCollection["MaxResults"].Value.ToString(), "", 0, ref bout);

            ComponentMetaData.FireInformation(0, "SSIS GoogleAnalyticsSource", "Service: " + Service.Credentials.ToString(), "", 0, ref bout);
            ComponentMetaData.FireInformation(0, "SSIS GoogleAnalyticsSource", "Service: " + Service.ProtocolMajor.ToString(), "", 0, ref bout);
            ComponentMetaData.FireInformation(0, "SSIS GoogleAnalyticsSource", "Service: " + Service.ProtocolMinor.ToString(), "", 0, ref bout);
            ComponentMetaData.FireInformation(0, "SSIS GoogleAnalyticsSource", "Service: " + Service.RequestFactory.ToString(), "", 0, ref bout);
            ComponentMetaData.FireInformation(0, "SSIS GoogleAnalyticsSource", "Service: " + Service.ServiceIdentifier.ToString(), "", 0, ref bout);

            ComponentMetaData.FireInformation(0, "SSIS GoogleAnalyticsSource", "Query: " + query.GAEndDate.ToString(), "", 0, ref bout);
            ComponentMetaData.FireInformation(0, "SSIS GoogleAnalyticsSource", "Query: " + query.BaseAddress.ToString(), "", 0, ref bout);
            ComponentMetaData.FireInformation(0, "SSIS GoogleAnalyticsSource", "Query: " + query.FeedFormat.ToString(), "", 0, ref bout);
            ComponentMetaData.FireInformation(0, "SSIS GoogleAnalyticsSource", "Query: " + query.PrettyPrint.ToString(), "", 0, ref bout);
            ComponentMetaData.FireInformation(0, "SSIS GoogleAnalyticsSource", "Query: " + query.Uri.ToString(), "", 0, ref bout);
            ComponentMetaData.FireInformation(0, "SSIS GoogleAnalyticsSource", "Query: " + query.Segment.ToString(), "", 0, ref bout);
            ComponentMetaData.FireInformation(0, "SSIS GoogleAnalyticsSource", "Query: " + query.Query.ToString(), "", 0, ref bout);
        }

        #endregion Helpers
    }
}